iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
0
Mobile Development

RxSwift / 30天探索之旅系列 第 12

第 12 天 - Share & ShareReplay

  • 分享至 

  • xImage
  •  

嗨,大家好,今天明明是禮拜六卻要上班的一天(笑),今天要講講share跟shareReplay,直接開始吧。

Share

Share是用來共享狀態,我們先看一個範例,沒加share的狀況。

現實中,我們常會call API,並共享API回傳的結果,我們然看看以下案例,假設讓refreshSubject收到事件後,會去觸發API,會有訂閱者會去觀察 API 回傳回來的結果,我們可能會這樣寫

let refreshSubject = PublishSubject<Void>()

let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }

result.debug("A").subscribe().disposed(by: disposeBag)

result.debug("B").subscribe().disposed(by: disposeBag)

refreshSubject.onNext(()) // 觸發 refresh

執行結果如下

A -> subscribed
B -> subscribed
Call API -> subscribed
Call API -> subscribed
Call API -> Event next(())
A -> Event next(())
Call API -> Event completed
Call API -> isDisposed
Call API -> Event next(())
B -> Event next(())
Call API -> Event completed
Call API -> isDisposed

可以發現 API 被呼叫兩次,也就是說每個訂閱者收到的元素都是新的,但有一種情況是,我想呼叫一次 API 就好,得到的結果讓其他觀察者共用,這時你可以在refreshSubject.flatMapLatest後面加上.share()

let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share()

執行結果如下

A -> subscribed
B -> subscribed
Call API -> subscribed
Call API -> Event next(())
A -> Event next(())
B -> Event next(())
Call API -> Event completed
Call API -> isDisposed

這時候 API 只會呼叫一次,並將結果共享給觀察者們。

ShareReplay

某些情境下,我們可能會發送元素之後才訂閱,或是在不同class訂閱到,這些都會導致我們訂閱時,收不到之前發送的元素,如果是這樣的情境的話,可以使用.share(replay, scope),replay意思就是會緩存n個元素,這點跟之前說過的ReplaySubject很像,所以就算延遲訂閱也可以收到緩存中的元素;scope,whileConnected(預設)跟forever,當沒Observable沒有Observer時,whileConnected會清除緩存,一切重來,forever則不會。

WhileConnected

延續上面的程式,我們改成這樣,多了一段延遲訂閱,從結果可以發現,在3秒後訂閱,還是可以收到Observable的結果

let refreshSubject = PublishSubject<Void>()

let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share(replay: 1)

result.debug("A").subscribe().disposed(by: disposeBag)

result.debug("B").subscribe().disposed(by: disposeBag)

refreshSubject.onNext(()) // 觸發 refresh
// 1
delay(3) {
    result
        .debug("shareReply")
        .subscribe()
        .disposed(by: self.disposeBag)
}

執行結果

26:32.172: A -> subscribed
26:32.174: B -> subscribed
26:32.174: Call API -> subscribed
26:34.176: Call API -> Event next(())
26:34.176: A -> Event next(())
26:34.176: B -> Event next(())
26:34.176: Call API -> Event completed
26:34.176: Call API -> isDisposed
26:35.175: shareReply -> subscribed
26:35.175: shareReply -> Event next(())

Forever

為了能展示把Observer銷毀,我們把我們delay時間拉長到6秒,並加入一個3秒後把disposeBag清除,從結果能看到,緩存是沒有清除的。

let refreshSubject = PublishSubject<Void>()

let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share(replay: 1, scope: .forever)

result.debug("A").subscribe().disposed(by: disposeBag)

result.debug("B").subscribe().disposed(by: disposeBag)

refreshSubject.onNext(()) // 觸發 refresh

delay(3) {
    self.disposeBag = DisposeBag()
}

delay(6) {
    result
        .debug("shareReply")
        .subscribe()
        .disposed(by: self.disposeBag)

執行結果

31:13.011: A -> subscribed
31:13.013: B -> subscribed
31:13.013: Call API -> subscribed
31:15.014: Call API -> Event next(())
31:15.015: A -> Event next(())
31:15.015: B -> Event next(())
31:15.015: Call API -> Event completed
31:15.015: Call API -> isDisposed
31:16.232: A -> isDisposed
31:16.233: B -> isDisposed
31:19.014: shareReply -> subscribed
31:19.014: shareReply -> Event next(())

今天講完Share,明天會講Combining,是最後的operator,一切都快結束了,加油!


上一篇
第 11 天 - Transforming Observables(下)
下一篇
第 13 天 - Combining Observables(上)
系列文
RxSwift / 30天探索之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言